package com.tiancheng.trade.settlement.task;

import com.tiancheng.trade.commom.core.utils.DateTimeUtil;
import com.tiancheng.trade.settlement.enums.BillStatusEnum;
import com.tiancheng.trade.settlement.exception.BusinessException;
import com.tiancheng.trade.settlement.model.settlement.SettlementBankWaitBill;
import com.tiancheng.trade.settlement.model.settlement.SettlementBillResult;
import com.tiancheng.trade.settlement.service.settlement.ISettlementBankWaitBillService;
import com.tiancheng.trade.settlement.service.settlement.ISettlementBillService;
import com.tiancheng.trade.settlement.util.JacksonJsonUtil;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 清分对账
 *
 * @author dell
 */
@Component
@Slf4j
public class SettlementBillTask {
    @Autowired
    private ISettlementBankWaitBillService settlementBankWaitBillService;
    @Autowired
    private ISettlementBillService settlementBillService;
    private final String format = "yyyy-MM-dd hh:mm:ss";
    @Resource
    private JacksonJsonUtil jacksonJsonUtil;
    /**
     * redis锁.
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 查询银行侧数据，未查询到说明是周末或节假日，不进行对账。
     * 查询到数据，跟平台侧数据进行对账，保存对账成功或异常的结果数据
     * 异常的数据，除金额异常外，还可能存在多种情况，逐一判断进行对应的处理
     * 保存或更新对账结果
     *
     * @param param
     * @return
     */
    @XxlJob("checkSettlement")
    public ReturnT<String> checkSettlement(String param) {
        long times = System.currentTimeMillis();
        try {
            Integer year = LocalDate.now().getYear();
            Integer month = LocalDate.now().getMonthValue();
            Integer day = LocalDate.now().getDayOfMonth();
            String key = year + "_" + month + "_" + day;
            String value = year + "" + month + "" + day;
            if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {
                //设置锁的时间为150秒，两分半钟
                stringRedisTemplate.expire(key, 150, TimeUnit.SECONDS);

                //获取银行侧待对账数据
                List<SettlementBankWaitBill> bankWaitBills = settlementBankWaitBillService.queryBankWaitBillList(BillStatusEnum.WAIT.getCode());
                //银行
                if (bankWaitBills == null || bankWaitBills.size() == 0) {
                    log.info("没有获取到银行待清分账单：{}", DateTimeUtil.getSystemDate(format));
                    return null;
                } else {
                    log.info("清分对账日期时间：{}", DateTimeUtil.getSystemDate(format));
                    log.info("清分对账开始:" + times);
                    List<String> subOrderKeys = new ArrayList<String>();
                    for (SettlementBankWaitBill bankWaitBill : bankWaitBills) {
                        //目前用子订单号+费用类型拼成唯一值，后续如果支持单笔子订单退款多次则需要修改
                        subOrderKeys.add(bankWaitBill.getSubOrderId() + bankWaitBill.getCostType() + bankWaitBill.getTradeType());
                    }
                    //	log.info("银行待对账数据:{}",jacksonJsonUtil.toJson(subOrderKeys));
                    //先将银行有的数据和我方有的数据对账
                    List<SettlementBillResult> results = settlementBillService.reconciliation(subOrderKeys);
                    if (!results.isEmpty()) {
                        log.info("对账完成可以保存的数据:{}", results.size());
                        settlementBillService.saveResult(results, subOrderKeys);
                        settlementBillService.updateErrorAmount(subOrderKeys);
                    }
                }
                //保存老系统子订单号为空的数据
                settlementBillService.saveBankSubOrderIsNullData();
            }
        } catch (Exception e) {
            log.error("清分对账 is fail", e.getMessage());
            e.printStackTrace();
        }
        log.info("清分对账结束:" + (System.currentTimeMillis() - times));
        return ReturnT.SUCCESS;
    }


    /**
     * 轮询我方有银行无的数据
     * 查询出我方未对账的数据
     * 到银行详情表查询，查询到的则对账，否则轮询次数加1
     * 此定时任务时间需要排在checkSettlement执行完毕以后
     */
    @XxlJob("settlementPolling")
    public ReturnT<String> polling(String param) {
        try {
            Integer year = LocalDate.now().getYear();
            Integer month = LocalDate.now().getMonthValue();
            Integer day = LocalDate.now().getDayOfMonth();
            String key = year + "_" + month + "_" + day;
            String value = year + "" + month + "" + day;
            if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {
                //设置锁的时间为150秒，两分半钟
                stringRedisTemplate.expire(key, 150, TimeUnit.SECONDS);
                log.info("定时任务处理我方有银行无的数据");
                int count = settlementBillService.polling();
                //保存我方有银行没有的数据
                settlementBillService.saveBankNothingException();
                log.info("定时任务查询我方有银行无的数据处理结果{}", count);
            }

        } catch (BusinessException e) {
            log.error("轮询我方有银行无的数据 is fail", e, e);
        }
        return ReturnT.SUCCESS;
    }
}
